package zouran.service.impl;

import org.gavaghan.geodesy.Ellipsoid;
import org.gavaghan.geodesy.GeodeticCalculator;
import org.gavaghan.geodesy.GeodeticCurve;
import org.gavaghan.geodesy.GlobalCoordinates;
import org.springframework.stereotype.Service;
import zouran.entity.EarthquakeInfo;
import zouran.entity.Estimate;
import zouran.mapper.EstimateMapper;
import zouran.service.EarthquakeInfoService;
import zouran.service.EstimateService;
import zouran.util.EstimateUtil;

import java.time.LocalDateTime;
import java.util.Map;

/**
 * Author：zouran
 * Date：2023/3/31  20:58
 * Description:
 */
@Service
public class EstimateServiceImpl implements EstimateService {
    private final EstimateMapper estimateMapper;
    private final EarthquakeInfoService earthquakeInfoService;
    private final EstimateUtil estimateUtil;

    public EstimateServiceImpl(EstimateMapper estimateMapper, EarthquakeInfoService earthquakeInfoService, EstimateUtil estimateUtil) {
        this.estimateMapper = estimateMapper;
        this.earthquakeInfoService = earthquakeInfoService;
        this.estimateUtil = estimateUtil;
    }

    @Override
    public double getPopulation(Double minLongitude, Double maxLongitude, Double minLatitude, Double maxLatitude) {
        return estimateMapper.getPopulation(minLongitude, maxLongitude, minLatitude, maxLatitude);
    }

    @Override
    public Estimate getEstimateResultByEarthquakeId(long earthquakeId) {
        if (!earthquakeInfoService.judgeEarthquakeInfoExistById(earthquakeId)) return null;
        int count = estimateMapper.judgeEstimateExist(earthquakeId);
        Estimate estimate = new Estimate();
        if (count == 0) {
            if (earthquakeInfoService.getEarthquakeInfoById(earthquakeId).getIntensityLineList().size() == 0) {
                estimate.setPredictDeath(0.0);
                estimate.setPredictEconomy(0.0);
                estimate.setEarthquakeId(earthquakeId);
                estimate.setPopulation(0);
                LocalDateTime date = LocalDateTime.now();
                estimate.setGmtCreate(date);
                estimateMapper.insert(estimate);
                return estimate;
            }
            EarthquakeInfo earthquakeInfo = earthquakeInfoService.getEarthquakeInfoById(earthquakeId);
            double magnitude = earthquakeInfo.getMagnitude(),
                    highIntensity = earthquakeInfo.getHighIntensity(),
                    longitude = earthquakeInfo.getLongitude(),
                    latitude = earthquakeInfo.getLatitude(),
                    longRadius = earthquakeInfo.getIntensityLineList().get(earthquakeInfo.getIntensityLineList().size() - 1).getLongRadius(),
                    shortRadius = earthquakeInfo.getIntensityLineList().get(earthquakeInfo.getIntensityLineList().size() - 1).getShortRadius();
//            System.out.println(longRadius);
            LocalDateTime earthquakeTime = earthquakeInfo.getEarthquakeTime();
            //将角度转换为弧度。
            double radians = Math.toRadians(latitude);
            double minLongitude = longitude - shortRadius / (111 - Math.cos(radians)),
                    maxLongitude = longitude + shortRadius / (111 - Math.cos(radians)),
                    minLatitude = latitude - longRadius / 111,
                    maxLatitude = latitude + longRadius / 111;
            int population = 1;
            try {
                population = (int) getPopulation(minLongitude, maxLongitude, minLatitude, maxLatitude);
            } catch (Exception ignored) {
            }
            estimate.setPredictDeath(estimateUtil.deathPredict(earthquakeInfo.getEarthquakeId(), population, magnitude, highIntensity, earthquakeTime, longitude, latitude));
            estimate.setPredictEconomy(estimateUtil.economyPredict(earthquakeInfo.getHighIntensity()));
            estimate.setEarthquakeId(earthquakeId);
            estimate.setPopulation(population);
            LocalDateTime date = LocalDateTime.now();
            estimate.setGmtCreate(date);
            estimateMapper.insert(estimate);
        } else {
            estimate = estimateMapper.selectById(earthquakeId);
        }
        return estimate;
    }

    @Override
    public Double getPointIntensity(Long earthquakeId, Double longitude, Double latitude) {
        Double intensity;
        EarthquakeInfo earthquakeInfo = earthquakeInfoService.getEarthquakeInfoById(earthquakeId);
        GlobalCoordinates source = new GlobalCoordinates(latitude, longitude);
        GlobalCoordinates target = new GlobalCoordinates(earthquakeInfo.getLatitude(), earthquakeInfo.getLongitude());
        GeodeticCurve geoCurve = new GeodeticCalculator().calculateGeodeticCurve(Ellipsoid.WGS84, source, target);
        Double meter = geoCurve.getEllipsoidalDistance();
        Double dividingLine = 105.1;
        if (earthquakeInfo.getLongitude() < dividingLine) {
            intensity = earthquakeInfo.getIntensityByDistance(5.253, 1.398, 4.164, 26, 0, meter);
        } else {
            intensity = earthquakeInfo.getIntensityByDistance(5.019, 1.446, 4.136, 24, 0, meter);
        }
        return intensity > 0 ? intensity : 0;
    }

    @Override
    public double getPopulationScope(Map<String, Double> scope) {
        double lontitude = scope.get("lontitude");
        double latitude = scope.get("latitude");

        double longRadius = scope.get("longRadius");
        double shortRadius = scope.get("shortRadius");

        double radians = Math.toRadians(latitude);

        double minLongitude = lontitude - shortRadius / (111 - Math.cos(radians)),
                maxLongitude = lontitude + shortRadius / (111 - Math.cos(radians)),
                minLatitude = latitude - longRadius / 111,
                maxLatitude = latitude + longRadius / 111;


        double populationden = 1;
        int population = 1;
        try {
            populationden = getPopulation(minLongitude, maxLongitude, minLatitude, maxLatitude);
            population = (int) (populationden*(longRadius+shortRadius)*4);
        } catch (Exception ignored) {
        }

        return population;
    }
}
